/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package debolezza4;

/**
 *
 * @author Davidenkow
 */
public class Match
{
	public static final int NROWS = 6;
	public static final int NCOLS = 7;
	public static final int MAXMOVES = NROWS * NCOLS;

	protected int [][] Grid;
	protected int MoveNum;

	protected int [][] WinnerLine;
	protected int WinnerPlayer;

	protected int MatchId;
	protected String MatchName;

	protected Player Player1;
	protected Player Player2;

	protected int CurrentPlayerId;

	public Match(int matchId, String matchName)
	{
		this.MatchId = matchId;
		this.MatchName = matchName;

		this.Grid = new int[NROWS][NCOLS];
		this.WinnerLine = new int[4][2];
		this.WinnerPlayer = 0;

		this.MoveNum = 0;

		this.CurrentPlayerId = 1;
	}

	protected void finish(int col, int row, int colStart, int rowStart)
	{
		this.WinnerLine[0][0] = rowStart;
		this.WinnerLine[0][1] = colStart;

		if (row < rowStart)
		{
			this.WinnerLine[1][0] = rowStart-1;
			this.WinnerLine[2][0] = rowStart-2;
			this.WinnerLine[3][0] = rowStart-3;
		}
		else if (row == rowStart)
		{
			this.WinnerLine[1][0] = rowStart;
			this.WinnerLine[2][0] = rowStart;
			this.WinnerLine[3][0] = rowStart;
		}
		else
		{
			this.WinnerLine[1][0] = rowStart+1;
			this.WinnerLine[2][0] = rowStart+2;
			this.WinnerLine[3][0] = rowStart+3;
		}

		if (col < colStart)
		{
			this.WinnerLine[1][1] = colStart-1;
			this.WinnerLine[2][1] = colStart-2;
			this.WinnerLine[3][1] = colStart-3;
		}
		else if (col == colStart)
		{
			this.WinnerLine[1][1] = colStart;
			this.WinnerLine[2][1] = colStart;
			this.WinnerLine[3][1] = colStart;
		}
		else
		{
			this.WinnerLine[1][1] = colStart+1;
			this.WinnerLine[2][1] = colStart+2;
			this.WinnerLine[3][1] = colStart+3;
		}

		this.WinnerPlayer = this.WinnerLine[0][0];
	}

	/**
	 * Rende effettiva la mossa del giocatore corrente.
	 * @param column Colonna dove inserire la pedina
	 * @return Riga entro la quale e' stata inserita la pedina
	 * @throws forza4.InvalidArgumentException
	 * @throws forza4.InvalidMoveException
	 */
	public int insert(int column) throws InvalidArgumentException, InvalidMoveException
	{
		int i;
		boolean out = true;

		if (column < 0 || column > NCOLS)
			throw new InvalidArgumentException("Colonna non valida.");

		for (i = NROWS; i > 0; i--)
		{
			if (this.Grid[i][column] == 0)
			{
				this.Grid[i][column] = this.CurrentPlayerId;
				out = false;
			}
		}
		if (out)
		{
			throw new InvalidMoveException("La colonna e' gia' completamente piena.");
		}
		this.MoveNum++;
		this.CurrentPlayerId = ((this.CurrentPlayerId + 1) % 2) + 1;
		return i;
	}

	/**
	 * Controlla se l'inserimento dell'ultima pedina causa la fine della partita.
	 * @param column
	 * @param row
	 * @return
	 */
	public boolean checkFinished(int col, int row)
	{
		boolean finished = false;
		int startx, stopx;
		int starty, stopy;
		int tlCorner, brCorner;
		int blCorner, trCorner;
		int i, n;
		int playerId = this.Grid[row][col];


		// controllo la verticale
		n = 0;
		starty = row - 3;
		stopy = row + 3;

		if (starty < 0)
			starty = 0;
		if (stopy >= NROWS)
			stopy = NROWS-1;

		for (i = stopy; i > starty; i--)
		{
			if (this.Grid[i][col] != playerId)
			{
				if (this.Grid[i][col] == 0)
					break;

				n = 0;
				// controllo se c'e' ancora la possibilita' di chiudere la colonna
				if (i <= 4)
					break;
			}
			else
			{
				n++;
				if (n == 4)
					finished = true;
			}
		}


		if (finished)
		{
			this.finish(col, row, col, i-4);
			return true;
		}

		// controllo l'orizzontale
		n = 0;
		startx = col - 3;
		stopx = col + 3;

		if (startx < 0)
			startx = 0;
		if (stopx >= NCOLS)
			stopx = NCOLS-1;

		for (i = startx; i < stopx; i++)
		{
			if (this.Grid[i][col] != playerId)
			{
				n = 0;
				// controllo se c'e' ancora la possibilita' di chiudere la colonna
				if (stopx - i <= 4)
					break;
			}
			else
			{
				n++;
				if (n == 4)
					finished = true;
			}
		}

		if (finished)
		{
			this.finish(col, row, i-4, row);
			return true;
		}

		// a questo punto le variabili startx, stopx, starty, stopy sono gia' inizializzate
		// il massimo numero di caselle diagonali da row, col in alto a sinistra
		tlCorner = this.min(col-startx, stopy-row);
		// il massimo numero di caselle diagonali da row, col in basso a destra
		brCorner = this.min(stopx-col, row-starty);

		// il massimo numero di caselle diagonali da row, col in alto a destra
		trCorner = this.min(stopx-col, stopy-row);
		// il massimo numero di caselle diagonali da row, col in basso a sinistra
		blCorner = this.min(col-startx, row-starty);

		n = 0;

		if (tlCorner + brCorner >= 4)
		{
			startx = col - tlCorner;
			starty = row + tlCorner;
			stopx = col + brCorner;
			stopy = row - brCorner;

			for (i = 0; i < tlCorner + brCorner; i++)
			{
				if (this.Grid[starty+i][startx+i] == playerId)
				{
					n++;
					if (n == 4)
					{
						finished = true;
						break;
					}
				}
				else
				{
					n = 0;
					if (tlCorner + brCorner - i <= 4)
						break;
				}
			}
		}
		if (finished)
		{
			this.finish(col, row, row+tlCorner, col-tlCorner);
			return true;
		}


		if (trCorner + blCorner >= 4)
		{
			startx = col - blCorner;
			starty = row + blCorner;
			stopx = col + trCorner;
			stopy = row - trCorner;

			for (i = 0; i < blCorner + trCorner; i++)
			{
				if (this.Grid[starty+i][startx+i] == playerId)
				{
					n++;
					if (n == 4)
					{
						finished = true;
						break;
					}
				}
				else
				{
					n = 0;
					if (trCorner + blCorner - i <= 4)
						break;
				}
			}
		}
		if (finished)
		{
			this.finish(col, row, row+tlCorner, col-tlCorner);
			return true;
		}

		if (this.MoveNum == MAXMOVES)
			return true;
		
		return false;
	}
	
	private int min(int x, int y)
	{
		return x > y ? y : x;
	}
}
